package com.nulldev.util.internal.unsafecompat;

import java.lang.reflect.Field;
import java.nio.ByteBuffer;

import com.nulldev.util.manage.RequiresJREVersion;

public interface IUnsafe {

	@RequiresJREVersion(reason = "VarHandle equivalent is available from JRE 9 and onwards.", version = 9)
	public long objectFieldOffset(final Field f);

	@RequiresJREVersion(reason = "VarHandle equivalent is available from JRE 9 and onwards.", version = 9)
	public Object getObject(Object o, long offset);

	@RequiresJREVersion(reason = "VarHandle equivalent is available from JRE 9 and onwards.", version = 9)
	public int getInt(Object o, long offset);

	@RequiresJREVersion(reason = "VarHandle equivalent is available from JRE 9 and onwards.", version = 9)
	public void putInt(Object o, long offset, int x);

	@RequiresJREVersion(reason = "VarHandle equivalent is available from JRE 9 and onwards.", version = 9)
	public void putObject(Object o, long offset, Object x);

	@RequiresJREVersion(reason = "VarHandle equivalent is available from JRE 9 and onwards.", version = 9)
	public void putOrderedObject(Object o, long offset, Object x);

	@RequiresJREVersion(reason = "VarHandle equivalent is available from JRE 9 and onwards.", version = 9)
	public void putOrderedInt(Object o, long offset, int x);

	@RequiresJREVersion(reason = "VarHandle equivalent is available from JRE 9 and onwards.", version = 9)
	public void putOrderedLong(Object o, long offset, long x);

	@RequiresJREVersion(reason = "VarHandle equivalent is available from JRE 9 and onwards.", version = 9)
	public boolean compareAndSwapObject(Object o, long offset, Object expected, Object x);

	@RequiresJREVersion(reason = "VarHandle equivalent is available from JRE 9 and onwards.", version = 9)
	public boolean compareAndSwapInt(Object o, long offset, int expected, int x);

	@RequiresJREVersion(reason = "VarHandle equivalent is available from JRE 9 and onwards.", version = 9)
	public boolean compareAndSwapLong(Object o, long offset, long expected, long x);

	@RequiresJREVersion(reason = "MemorySegment equivalent is available from JRE 22 and onwards.", version = 22)
	public int arrayBaseOffset(Class<?> arrayClass);

	@RequiresJREVersion(reason = "MemorySegment equivalent is available from JRE 22 and onwards.", version = 9)
	public int arrayIndexScale(Class<?> arrayClass);

	@RequiresJREVersion(reason = "VarHandle equivalent is available from JRE 9 and onwards.", version = 9)
	public void loadFence();

	@RequiresJREVersion(reason = "VarHandle equivalent is available from JRE 9 and onwards.", version = 9)
	public void storeFence();

	@RequiresJREVersion(reason = "VarHandle equivalent is available from JRE 9 and onwards.", version = 9)
	public void fullFence();

	@RequiresJREVersion(reason = "VarHandle equivalent is available from JRE 9 and onwards.", version = 9)
	public long getLongVolatile(Object o, long offset);

	@RequiresJREVersion(reason = "VarHandle equivalent is available from JRE 9 and onwards.", version = 9)
	public default Object getAndSetObject(Object o, long offset, Object newValue) {
		Object v;
		do {
			v = getObjectVolatile(o, offset);
		} while (!compareAndSwapObject(o, offset, v, newValue));
		return v;
	}

	@RequiresJREVersion(reason = "VarHandle equivalent is available from JRE 9 and onwards.", version = 9)
	public default long getAndAddLong(Object o, long offset, long delta) {
		long v;
		do {
			v = getLongVolatile(o, offset);
		} while (!compareAndSwapLong(o, offset, v, v + delta));
		return v;
	}

	@RequiresJREVersion(reason = "VarHandle equivalent is available from JRE 9 and onwards.", version = 9)
	public Object getObjectVolatile(Object o, long offset);

	@RequiresJREVersion(reason = "VarHandle equivalent is available from JRE 9 and onwards.", version = 9)
	public void putObjectVolatile(Object o, long offset, Object x);

	@RequiresJREVersion(reason = "VarHandle equivalent is available from JRE 9 and onwards.", version = 9)
	public int getIntVolatile(Object o, long offset);

	/* Memory allocation bullshit (MemorySegment required, JRE22+) */

	@RequiresJREVersion(reason = "MemorySegment equivalent is available from JRE 22 and onwards.", version = 22)
	public byte getByte(long address);

	@RequiresJREVersion(reason = "MemorySegment equivalent is available from JRE 22 and onwards.", version = 22)
	public void putByte(long address, byte x);

	@RequiresJREVersion(reason = "MemorySegment equivalent is available from JRE 22 and onwards.", version = 22)
	public void putInt(long address, int x);

	@RequiresJREVersion(reason = "MemorySegment equivalent is available from JRE 22 and onwards.", version = 22)
	public int getInt(long address);

	@RequiresJREVersion(reason = "Arena equivalent is available from JRE 20 and onwards.", version = 20)
	public long allocateMemory(long bytes);

	@RequiresJREVersion(reason = "MemorySegment equivalent is available from JRE 22 and onwards.", version = 22)
	public long reallocateMemory(long address, long bytes);

	@RequiresJREVersion(reason = "MemorySegment equivalent is available from JRE 22 and onwards.", version = 22)
	public void setMemory(Object o, long offset, long bytes, byte value);

	@RequiresJREVersion(reason = "MemorySegment equivalent is available from JRE 22 and onwards.", version = 22)
	public default void setMemory(long address, long bytes, byte value) {
		setMemory(null, address, bytes, value);
	}

	@RequiresJREVersion(reason = "Arena equivalent is available from JRE 20 and onwards.", version = 20)
	public void freeMemory(long address);

	/* Misc. */

	public boolean tryInvokeCleaner(final ByteBuffer bb);
}
